<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <!-- 视图层 -->
    <!-- <p>{{str}}</p>
    <p>{{num}}</p>
    <p>{{bool}}</p> -->
    <div id="app">
        <p>{{str}}---{{num}}---{{bool}}</p>
    </div>
</body>
<script>
    // Vue的特征
    // 1. 声明式渲染
    //    Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统：(可以理解为new Vue创建Vue实例时,会将#app元素内的html结构作为模版, 将数据(data)拼接到模版中, 渲染为DOM)
    //    {{}} => 文本插值 => 在标签对的内部使用 => 将数据拼接到标签内

    // 2. 响应式  => 当数据发生改变时, 视图也会重新渲染(跟新)

    // console.log(Vue);    // 构造函数

    function MyVue(options) { // options = {el,data,template,methods}
        // {}
        // {}[[Prototype]] = MyVue.prototype
        // this -> {}

        let { el, data } = options;
        this.$el = document.querySelector(el);
        let defaultTemplate = this.$el.innerHTML;

        // 数据拦截 (数据劫持) 
        // data => 对象(数据)  => 对data的取值和赋值进行拦截(数据劫持) 
        // let defaultValue = data["str"];
        // Object.defineProperty(data,"str",{
        //     get:function(){ // 取值拦截
        //         return defaultValue;
        //     },
        //     set:function(val){
        //         defaultValue = val;
        //     }
        // })

        // for (let key in data) { // 遍历data
        //     let defaultValue = data[key]; // 提前声明变量存储数据
        //     Object.defineProperty(data, key, {
        //         get: function () { // 取值拦截
        //             console.log("data取值拦截",key);
        //             return defaultValue;
        //         },
        //         set: function (val) { // 赋值拦截
        //             console.log("data赋值拦截",key,val);
        //             defaultValue = val;

        //             render(); // 数据发生改变之后 -> 重新渲染
        //         }
        //     })
        // }

        // 给Vue实例添加数据拦截 => 属性和data上的属性保持一致
        // for (let key in data) { // 遍历data
        //     Object.defineProperty(this, key, {
        //         get: function () { // 取值拦截
        //             console.log("实例化对象取值拦截",key);
        //             return data[key];
        //         },
        //         set: function (val) { // 赋值拦截
        //             console.log("实例化对象赋值拦截",key,val);
        //             data[key] = val;
        //         }
        //     })
        // }


        this.$data = data;
        var _this = this;

        render();

        function render() {
            let html = defaultTemplate; // html默认模版
            console.log("html", html);


            // 正则匹配字符串  {{xxx}}
            let reg = /\{\{(\w+)\}\}/g; // {{xxx}}

            // let result = reg.exec(html); // 将符合规则的内容提取出来放到数组中  => 存在就返回数组  不存在 => null
            // console.log(result);  // ["{{str}}","str"]

            // let replacedStr = result[0]; // {{str}}
            // let key = result[1];
            // html = html.replace(replacedStr,data[key]); // 用替换后的新字符串覆盖原本的字符串

            let result = null;
            while (result = reg.exec(html)) {  // 先执行exec() 将结果赋值给result ,在将result作为循环条件
                // result  => [] / null 
                console.log(result);
                let replacedStr = result[0]; // {{str}}
                let key = result[1];
                html = html.replace(replacedStr, data[key]);

            }

            console.log(html);

            _this.$el.innerHTML = html;

            // console.log(1+1);
            // console.log(2);
            // console.log(String(100));

        }

        // return this;
    }


    // 声明式渲染
    var app = new MyVue({  // 创建Vue实例
        el: "#app",   // 挂载的元素
        data: { // 数据层 => 对应属性名将属性值 拼接到模版语法中
            str: "hello Vue",
            num: 100,
            bool: true,
        }
    })

    console.log(111, app);

    //  2. 响应式  => 当数据发生改变时, 视图也会重新渲染(更新)
    // setTimeout(() => {
    //     app.$data.str = "Vue Hello";
    //     app.$data.num = 200;
    //     app.$data.bool = false;
    //     console.log("修改完毕");
    // }, 2000)

    //  为了获取和修改数据更加方便, Vue实例中也会绑定同名属性, 此属性的取值和赋值都依赖于$data上的对应属性
    setTimeout(() => {
        app.str = "Vue Hello";
        app.num = 200;
        app.bool = false;
        console.log("修改完毕");
    }, 2000)











</script>

</html>